Skip to content

websocket 要点梳理

websocket

shell
# 1. wss 协议需要向 https 证书一样去供应商买吗?如何配置 wss?
wss 本质 = ws + TLS/SSL 加密
不需要单独买 WSS 证书,你网站的 HTTPS 域名 SSL 证书 直接复用即可
只要域名配置了 HTTPS 并绑定 SSL 证书,天然支持 wss

# 2. WebSocket 心跳机制是什么?为什么需要?如何实现?
心跳机制
    客户端定时发 ping 包,服务端收到立刻回 pong,设定超时时间,没收到 pong 判定掉线 关闭连接 触发重连
作用/原因/目的
    其一防止防火墙静默断开:运营商、防火墙、Nginx 都会有空闲超时,连接长时间没数据,会主动掐断 TCP 通道,但前端、后端都感知不到,变成假连接。
    其二识别 “假连接”:所谓假连接表面上连接还在,实际网络已经断开,用户断网、切网、程序闪退、网络波动,WebSocket 不一定立刻触发 onclose,靠心跳超时判断客户端已离线,主动清理连接、下线状态、释放资源。
注意
    关闭 socket 的时候,清理定时器
    

# 4. WebSocket 重连怎么实现?
要点速览
    监听断开事件 --- 加延迟-防止多频触发 --- 加锁-防止重复触发 --- 重连后恢复状态
具体 
    监听 onclose onerror 事件,当连接断开或异常时触发重连;
    使用延迟重试,避免频繁重连压垮服务器;
    增加重连锁,防止同时发起多个重连;
    重连成功后,重新绑定事件监听、重新加入房间,恢复业务状态;
注意
    Socket.IO 已内置自动重连,可配置断线自动重连、最大重连数、重连间隔,自动实现无需手写
        
# 5. WebSocket 跨域吗?
WebSocket 浏览器端不限制跨域,不受同源策略影响,但生产环境下服务端通常会主动限制 Origin,从而产生了“跨域处理”的必要。
最佳实践是用反向代理让前后端同域
或者服务端显式配置允许的域名。

# 6. wss 和 ws 区别?生产用哪个?
ws 明文、80 端口
wss 加密、443 端口 = ws + TLS
网页如果是 https 打开的,浏览器强制禁止连接 ws:// 明文,必须用 wss://
ws:// https 网站直接被浏览器禁止
wss 加密、更安全、不被运营商劫持
所以:生产必须用 wss

# 7. WebSocket 如何做鉴权?
方案 1. 握手 URL query 参数 wss://xx/ws?token=xxx(简单但日志泄露)
方案 2. 请求头 Header 携带 Token(握手时带 Authorization)
方案 3. Sec-WebSocket-Protocol 子协议头 夹带编码后的 token
方案 4. 连接建立后第一条业务消息传 token 鉴权
方案 5. Socket.IO 优先用:handshake.auth token,不暴露在 URL。
    新版本的 socket.io 中,创建 socket 实例的时候传入 {auth: {token: "xxx"}} 参数,旧版本依然是 query,不安全

# 8. WebSocket 会丢包/乱序吗?
丢包
    TCP 可靠传输,不会丢包,但断开重连期间消息可能丢失,需业务层做消息确认 / 重发
乱序
    业务可加 消息序号 seq 处理乱序:每条消息带一个自增唯一序号 seq,接收端维护一个 期待的下一个序号 expectedSeq
        等于期待序号 立即处理
        大于期待序号 暂存到缓存区
        小于期待序号 丢弃(重复 / 过时)

# 9. 断开重连期间消息丢失怎么处理?
客户端本地缓存未送达消息,连接恢复后自动重发;
服务端做 ACK 回执,已处理的消息拒绝重复执行业务;

# 9. 大量 WebSocket 连接服务器怎么扛?
1. 调高服务器文件句柄数(ulimit),这个直接关系到 websocket 的最大连接数
2. 使用高性能框架(Node.js (ws)、Go、Netty
3. 空闲连接心跳检测,超时清理僵尸连接,关闭无效心跳、压缩消息、减少内存占用。

# 9. WebSocket 分布式水平扩展怎么做?
Nginx 负载均衡,配置 ip_hash 会话粘滞,同一客户端始终调度到同一台 WS 节点;
所有 WS 节点接入 Redis Pub/Sub 发布订阅;
节点收到消息发布到 Redis,所有节点订阅消费,各自推送给本地在线客户端;
大型集群用 Redis 存储 用户 ID 所在节点,定向推送,减少广播压力。

# 10. 为什么 WebSocket 不能直接 Nginx 轮询?
长连接一旦建立就绑定某一台服务节点;轮询会导致客户端重连分到另一台机器,丢失原有连接会话、房间、状态,消息推不到用户。必须会话粘滞。


# 11. WebSocket 握手过程?
基于 HTTP 协议一次升级握手:
    客户端发 HTTP 请求,携带:
        Connection: Upgrade
        Upgrade: websocket
        Sec-WebSocket-Key 随机密钥
        Sec-WebSocket-Version
    服务端返回 101 Switching Protocols;
    服务端把 Key 拼接固定字符串做 SHA1 加密,返回 Sec-WebSocket-Accept;
    客户端校验通过,成功升级为 WebSocket 长连接。

# 12. WebSocket 默认端口?加密版本?
明文:ws:// 默认 80
加密:wss:// 默认 443
wss 基于 TLS 加密,和 HTTPS 一样,防劫持、防抓包。

# 轮询 / 长轮询 / SSE / WebSocket 对比
短轮询:客户端定时发 HTTP 请求,服务端立即返回,不管有无数据;开销大、延迟高。
长轮询:客户端请求挂起,服务端有数据才响应,响应后客户端立刻再建请求;基于 HTTP,适配好,只能服务端单向推。
WebSocket:TCP 长连接、全双工、低开销、真正实时,适合聊天、大屏、游戏、IM。
SSE:单向服务端推送,基于 HTTP,只能服务端发、客户端收,不支持双向。

websocket 与 HTTP

shell
# 1. websocket 与 HTTP 的关系?
WebSocket 建立连接时用 HTTP 握手,连接成功后彻底脱离 HTTP,ws 走独立协议
请求头包含:Upgrade: websocket、Connection: Upgrade

# 2. http 优缺点
优点
   单向短连接 用完就释放,压力可控。适合用完即走的接口,业务中大部分业务场景更适合使用 http 请求
缺点
   单向短连接,只能客户端主动发请求、服务端被动应答,服务端不能主动向客户端推送数据;每次请求完成立即断开,无持久长连接。双端实时通信表现弱

# 3. WebSocket 优缺点?
优点
    双向长连接、一次握手建立持久双向长连接,通道一直保持、轻量级协议头开销小、支持文本/二进制、支持跨域。
    支持服务端主动推送、低延迟、开销小、节省流量、服务端压力小,特别适合聊天、通知、实时大屏、对战游戏等实时场景。
缺点
    每一个客户端都占一条长连接,在线用户多了服务器连接数、内存压力暴涨,不适合用完即走的需求

# 4. websocket 一定比 http 好用吗? 整个系统可以都换成 websocket 通信吗?
不行,websocket 缺点比较明显,每一个客户端都占一条长连接,且一直保持连接不断开,在线用户多了服务器连接数、内存压力暴涨
企业级标准做法:普通接口用 HTTP,实时推送用 WebSocket

# 5. WebSocket 和 HTTP 的区别?
HTTP 单向、短连接、无状态
WebSocket 双向、长连接、服务器可主动推送
WebSocket 握手用 HTTP,之后独立协议

Socket.IO 专项梳理

shell
# Socket.IO 和原生 WebSocket 区别?
Socket.IO 是封装库,底层可降级轮询,兼容低版本浏览器;原生 WebSocket 是标准协议。
自带自动重连、心跳、房间、ACK 回执,原生需要自己实现。
Socket.IO 有自定义握手、auth 鉴权、分布式适配器;原生都要手写。
自带断线容错、消息缓存。

# Socket.IO 断线重连原理?
定时心跳检测(ping/pong),超时没响应判定断线;自动重试握手,重连成功后恢复房间、同步状态。